package com.jasonchoi.security.config;

import com.jasonchoi.security.handler.LoginFailureHandler;
import com.jasonchoi.security.handler.LoginSuccessHandler;
import com.jasonchoi.security.handler.LoginedAccessDeniedHandler;
import com.jasonchoi.security.handler.NotLoginAccessDeniedHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @Author: JasonChoi
 * @Date: 2019/12/31 14:48
 */
@EnableGlobalMethodSecurity(securedEnabled = true, jsr250Enabled = true, prePostEnabled = true) //开启方法级别的security
@EnableWebSecurity //写不写好像都默认会开启security功能
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    /**
     * 可配置Spring Security的Filter链
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
    }

    /**
     * 可配置如何通过拦截器保护请求
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()
            .antMatchers("/", "/home")
            .permitAll()
            .anyRequest()
            .authenticated();

        /**
         * 登录配置 支持json登录登出-前后端分离
         * 函数式接口的写法 https://www.jianshu.com/p/650a497b3a40
         */
        http.formLogin()
            .usernameParameter("username").passwordParameter("password").loginProcessingUrl("/login")
            .successHandler(new LoginSuccessHandler())
            .failureHandler(new LoginFailureHandler())
            .permitAll()
            .and()
            .logout()
            .permitAll();

        /**
         * 权限不足处理
         * AuthenticationEntryPoint 用来解决匿名用户访问无权限资源时的异常
         * AccessDeineHandler 用来解决认证过的用户访问无权限资源时的异常
         */
        http.exceptionHandling()
            .accessDeniedHandler(new LoginedAccessDeniedHandler())
            .authenticationEntryPoint(new NotLoginAccessDeniedHandler());

        //开启跨域 关闭csrf
        http.cors().and().csrf().disable();
    }

    /**
     * 可配置user-detail（用户详细信息）服务
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            //不使用密码编解码
            //.withUser("user").password("{noop}1234").roles("USER").and()
            .passwordEncoder(new BCryptPasswordEncoder())
            .withUser("user").password(new BCryptPasswordEncoder().encode("123")).roles("USER").and()
            .withUser("admin").password(new BCryptPasswordEncoder().encode("456")).roles("USER", "ADMIN");
    }


    /**
     * 跨域 支持
     *
     * @return
     */
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**");
            }
        };
    }
}
